home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / executor / aggregate.c next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.1 KB  |  438 lines

  1. /* ------------------------------------------------
  2.  *   FILE
  3.  *     aggregate.c
  4.  *
  5.  *   DESCRIPTION
  6.  *    Routines to handle aggregate nodes.
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *    ExecAgg            -generate a temporary relation
  10.  *    ExecInitAgg        -initialize node and subnodes..
  11.  *    ExecEndAgg        -shutdown node and subnodes
  12.  *
  13.  *  NOTES  
  14.  *    this is a new file, jc
  15.  *
  16.  *   IDENTIFICATION
  17.  *       $Header: /private/postgres/src/executor/RCS/aggregate.c,v 1.15 1992/08/04 17:37:40 mer Exp $ *?*
  18.  * ------------------------------------------------
  19.  */
  20.  
  21. #include "executor/executor.h"
  22. #include "catalog/pg_protos.h"
  23.  
  24.  RcsId("Header: RCS/aggregate.c,v 1.1 91/07/28 15:02:49 caetta Exp $");
  25. /* ---------------------------------------
  26.  *    ExecAgg
  27.  *
  28.  *    ExecAgg receives tuples from its outer subplan and
  29.  *     aggregates over the appropriate attribute until the clause
  30.  *    attribute contents change, if there is a clause attribute.
  31.  *    It then finalizes and stores the aggregated tuple into a second
  32.  *    temp class, and goes on to aggregate the next set.  When the outer
  33.  *    subplan runs out of tuples, the procedure exits and returns the
  34.  *    name of the temporary relation that holds the aggregated tuples.
  35.  *    I'm not relying on the negative relid to identify it because of
  36.  *    the possibility of more than one temp relation being created during
  37.  *    a query.
  38.  *    Initial State:
  39.  *
  40.  *    ExecAgg expects a tempRelation to have been created to hold
  41.  *    the aggregated tuples whose id is stored in the aggregate node.
  42.  * ------------------------------------------
  43.  */
  44. /* convenient routine...
  45. */
  46.  
  47. /*-----------------------------------------------------------------------
  48.  * find the attribute No from the tuple descriptor and the
  49.  * attribute name. 'nattrs' is the # of attributes in the relation.
  50.  *-------------------------------------------------------
  51.  
  52. /*
  53. AttributeNumber
  54. findAttrNoFromName(tupdesc, nattrs, name)
  55. TupleDescriptor tupdesc;
  56. AttributeNumbers nattrs;
  57. Name name;
  58. {
  59.     int i;
  60.  
  61.     for(i=0; i<nattrs; i++) {
  62.           if (!strcmp (&(name->data[0]), &(tupdesc->data[i]->attname.data[0])))
  63.         return((AttributeNumber)(i+1));
  64.     }
  65.  
  66.     elog(WARN, "findAttrNoFromName: No such attribute (name = %s)",
  67.         name);
  68. }
  69. */
  70.  
  71. /**** xxref:
  72.  *        ExecProcNode
  73.  ****/
  74. TupleTableSlot        /* this is debatable */
  75. ExecAgg(node)
  76.     Agg node;
  77. {
  78.     EState        estate;
  79.     AggState        aggstate;
  80.     Plan        outerNode;
  81.     HeapTuple        outerTuple;
  82.     TupleDescriptor    outerTupDesc;
  83.     HeapTuple        heapTuple;
  84.     TupleTableSlot    outerslot;
  85.     Relation        tempRelation;
  86.     extern Datum     fastgetattr();
  87.     char        *running_comp[2];
  88.     char         *final_value;
  89.     TupleDescriptor     aggtupdesc;
  90.     TupleTableSlot    slot;
  91.     String         aggname;
  92.     bool        isNull = 0;
  93.     ObjectId        func1, func2, finalfunc;
  94.     char         nulls = ' ';
  95.     char         *theNewVal;
  96.     int            nargs[3];
  97.     long        nTuplesAgged = 0;
  98.     func_ptr        functionptrarray[3];
  99.     char         *args[2];
  100.  
  101.     /* ------------
  102.      *  get state info from node
  103.      * ------------
  104.      */
  105.     aggstate =         get_aggstate((Agg) node);
  106.     estate =         (EState) get_state((Plan) node);
  107.  
  108.     /* the first time we call this we aggregate the tuples below.
  109.      * subsequent calls return tuples from the temp relation
  110.      */
  111.     if(get_agg_Flag(aggstate) != false)
  112.     return (NULL); 
  113.  
  114.     SO1_printf("ExecAgg: %s\n", "aggstate == false -> aggregating subplan");
  115.  
  116.     set_es_direction(estate, EXEC_FRWD);
  117.  
  118.     /* ---------------------
  119.      * if we couldn't create the temp or current relations then
  120.      * we print a warning and return NULL.
  121.      * ----------------------
  122.      */
  123.     tempRelation = get_agg_TempRelation((AggState) aggstate);
  124.     if (tempRelation == NULL) 
  125.     {
  126.     elog(DEBUG, "ExecAggregate: temp relation is NULL! aborting...");
  127.     return NULL;
  128.     }
  129.  
  130.     outerNode = get_outerPlan((Plan) node);
  131.     aggtupdesc = ExecGetResultType((CommonState) aggstate);
  132.     aggname = (String)get_aggname(node);
  133.  
  134.     func1 = CInteger((LispValue)SearchSysCacheGetAttribute(AGGNAME,
  135.                         Anum_pg_aggregate_xitionfunc1,
  136.                         aggname,
  137.                         0, 0, 0));
  138.     if (!func1)
  139.     elog(WARN, "Missing xition function 1 for aggregate %s", aggname);
  140.  
  141.     func2 = CInteger((LispValue)SearchSysCacheGetAttribute(AGGNAME,
  142.                         Anum_pg_aggregate_xitionfunc2,
  143.                         aggname,
  144.                         0, 0, 0));
  145.  
  146.     finalfunc = CInteger((LispValue)SearchSysCacheGetAttribute(AGGNAME, 
  147.                             Anum_pg_aggregate_finalfunc,
  148.                             aggname,
  149.                             0, 0, 0));
  150.  
  151.     fmgr_info(func1, &functionptrarray[0], &nargs[0]);
  152.  
  153.     /* -----------
  154.      * If this agg has a 2nd xition function get it and its initial value
  155.      * -----------
  156.      */
  157.     if (func2)
  158.     {
  159.     fmgr_info(func2, &functionptrarray[1], &nargs[1]);
  160.     running_comp[1] = (char *)
  161.         AggNameGetInitVal(aggname, Anum_pg_aggregate_initsecval, &isNull);
  162.  
  163.     if (isNull)
  164.         elog(WARN,
  165.          "Aggregate has no initial value for the 2nd xition function");
  166.     }
  167.  
  168.     if (finalfunc)
  169.     fmgr_info(finalfunc, &functionptrarray[2], &nargs[2]);
  170.  
  171.     /* ------------------------------------------
  172.      * Get the intial value for the aggregate's running computation.
  173.      * If one doesn't exist in the pg_aggregate table then the first
  174.      * value returned from the outer procNode becomes the initial value.
  175.      * (This is useful for aggregates like max{} and min{})
  176.      * ------------------------------------------
  177.      */
  178.     running_comp[0] = (char *)
  179.     AggNameGetInitVal(aggname, Anum_pg_aggregate_initaggval, &isNull);
  180.     while (isNull)
  181.     {
  182.     outerslot = ExecProcNode(outerNode);
  183.     outerTuple = (HeapTuple) ExecFetchTuple((Pointer) outerslot);
  184.     if(outerTuple == NULL)
  185.         elog(WARN, "No initial value *and* no values to aggregate");
  186.      outerTupDesc = (TupleDescriptor)SlotTupleDescriptor(outerslot);
  187.  
  188.     /* ------------
  189.      * find an initial value.
  190.      * ------------
  191.      */
  192.     running_comp[0] = (char *)
  193.         fastgetattr(outerTuple, 1, outerTupDesc, &isNull);
  194.  
  195.     /* -------------
  196.      * xition function 2 must be run for each outerProcNode tuple.
  197.      * -------------
  198.      */
  199.     if (func2) 
  200.     {
  201.         running_comp[1] = (char *)
  202.         fmgr_by_ptr_array_args( functionptrarray[1],
  203.                     nargs[1],
  204.                     &running_comp[1], &isNull) ;
  205.     }
  206.     }
  207.     
  208.     for(;;) 
  209.     {
  210.     outerslot = ExecProcNode(outerNode);
  211.     
  212.     outerTuple = (HeapTuple) ExecFetchTuple((Pointer) outerslot);
  213.     if(outerTuple == NULL)
  214.         break;
  215.      outerTupDesc = (TupleDescriptor)SlotTupleDescriptor(outerslot);
  216.  
  217.     /* 
  218.      * continute to aggregate 
  219.      */
  220.     theNewVal = (char *)fastgetattr(outerTuple, 1, outerTupDesc, &isNull);
  221.  
  222.     args[0] = running_comp[0];
  223.     args[1] = theNewVal;
  224.     running_comp[0] = (char *) 
  225.         fmgr_by_ptr_array_args( functionptrarray[0],
  226.                     nargs[0],
  227.                     &args[0], &isNull );
  228.     /* ----------
  229.      * We aggregated another tuple
  230.      * ----------
  231.      */
  232.     nTuplesAgged++;
  233.  
  234.     if (func2) 
  235.     {
  236.         running_comp[1] = (char *)
  237.         fmgr_by_ptr_array_args( functionptrarray[1],
  238.                     nargs[1],
  239.                     &running_comp[1], &isNull );
  240.     }
  241.     }
  242.  
  243.     /* --------------
  244.      * finalize the aggregate (if necessary), and get the resultant value
  245.      * --------------
  246.      */
  247.     if (finalfunc && nTuplesAgged > 0)
  248.     {
  249.     final_value = (char *)
  250.         fmgr_by_ptr_array_args( functionptrarray[2],
  251.                     nargs[2],
  252.                     &running_comp[0], &isNull );
  253.     }
  254.     else
  255.     final_value = running_comp[0];
  256.  
  257.     heapTuple = heap_formtuple( 1,
  258.                 aggtupdesc,
  259.                 &final_value,
  260.                 &nulls );
  261.  
  262.     slot = (TupleTableSlot) get_cs_ResultTupleSlot((CommonState) aggstate);
  263. /*
  264.  * Unclear why this is being done -- mer 4 Nov. 1991
  265.  *
  266.  *  ExecSetSlotDescriptor(slot, &tempRelation->rd_att);
  267.  */
  268.     set_agg_Flag(aggstate, true);
  269.     return (TupleTableSlot)
  270.     ExecStoreTuple((Pointer) heapTuple,
  271.                (Pointer) slot,
  272.                InvalidBuffer,
  273.                false);
  274. }
  275.  
  276. /* -----------------
  277.  * ExecInitAgg
  278.  *
  279.  *  Creates the run-time information for the agg node produced by the
  280.  *  planner and initializes its outer subtree
  281.  * -----------------
  282.  */
  283. /* xxref
  284.  *     ExecInitNode
  285.  */
  286. List
  287. ExecInitAgg(node, estate, parent)
  288.     Agg     node;
  289.     EState    estate;
  290.     Plan    parent;
  291. {
  292.     AggState        aggstate;
  293.     Plan        outerPlan;
  294.     TupleDescriptor    tupType;
  295.     ObjectId        tempOid;
  296.     ObjectId        aggOid;
  297.     Relation        tempDesc;
  298.     ParamListInfo    paraminfo;
  299.     ExprContext        econtext;
  300.     int            baseid;
  301.     int            len;
  302.  
  303.     SO1_printf("ExecInitAgg: %s\n", "initializing agg node");
  304.  
  305.     /* 
  306.      * assign the node's execution state
  307.      */
  308.  
  309.     set_state((Plan) node,  (EStatePtr)estate);
  310.  
  311.     /*
  312.      * create state structure
  313.      */
  314.  
  315.     aggstate = MakeAggState(false,NULL,NULL); /* values will be squished
  316.                       *  anyway
  317.                       */
  318.     set_aggstate(node, aggstate);
  319.  
  320.     /*
  321.      * Should Aggregate nodes initialize their ExprContexts?
  322.      * not for now until we can do quals
  323.      */
  324.  
  325.     ExecAssignNodeBaseInfo(estate, (BaseNode) aggstate, (Plan) parent);
  326.     ExecAssignDebugHooks((Plan) node, (BaseNode) aggstate);
  327.  
  328. #define AGG_NSLOTS 2
  329.     /*
  330.      * tuple table initialization
  331.      */
  332.     ExecInitScanTupleSlot(estate, (CommonScanState) aggstate);
  333.     ExecInitResultTupleSlot(estate, (CommonState) aggstate);
  334.  
  335.     /*
  336.      * initializes child nodes
  337.      */
  338.     outerPlan = get_outerPlan((Plan) node);
  339.     ExecInitNode( outerPlan,estate,(Plan)node);
  340.  
  341.     /*
  342.      * initialize aggstate information
  343.      */
  344.     set_agg_Flag(aggstate, false);
  345.  
  346.     /*
  347.      * Initialize tuple type for both result and scan.
  348.      * This node does no projection
  349.      */
  350.     ExecAssignResultTypeFromTL((Plan) node, (CommonState) aggstate);
  351.     ExecAssignScanTypeFromOuterPlan((Plan) node, (CommonState) aggstate);
  352.     set_cs_ProjInfo((CommonState) aggstate, (ProjectionInfo) NULL);
  353.  
  354.     /*
  355.      * get type information needed for ExecCreatR
  356.      */
  357.  
  358.     tupType = ExecGetScanType((CommonScanState) aggstate);
  359.     tempOid = get_tempid((Temp)node);
  360.     aggOid = -1;
  361.  
  362.     /*
  363.      * create temporary relations
  364.      */
  365.  
  366.     len =        ExecTargetListLength(get_qptargetlist((Plan) node));
  367.     tempDesc =        ExecCreatR(len, tupType, tempOid);
  368.  
  369.     /*
  370.      * save the relation descriptor in the sortstate
  371.      */
  372.  
  373.     set_agg_TempRelation(aggstate, tempDesc);
  374.     SO1_printf("ExecInitSort: %s\n", "sort node initialized");
  375.  
  376.     return LispTrue;
  377. }
  378.  
  379. int
  380. ExecCountSlotsAgg(node)
  381.     Plan node;
  382. {
  383.     return ExecCountSlotsNode(get_outerPlan(node)) +
  384.        ExecCountSlotsNode(get_innerPlan(node)) +
  385.        AGG_NSLOTS;
  386. }
  387.  
  388. /* ------------------------
  389.  *    ExecEndAgg(node)
  390.  *
  391.  *     destroys the temporary relation
  392.  * -----------------------
  393.  */
  394.  
  395. /*** xxref:
  396.  *    ExecEndNode
  397.  ****/
  398. void
  399. ExecEndAgg(node)
  400.     Agg node;
  401. {
  402.     AggState    aggstate;
  403.     Relation    tempRelation;
  404.     Plan    outerPlan;
  405.  
  406.     /* get info from aggstate */
  407.  
  408.     SO1_printf("ExecEndSort: %s\n",
  409.            "shutting down sort node");
  410.  
  411.     aggstate =        get_aggstate(node);
  412.     tempRelation = get_agg_TempRelation(aggstate);
  413.  
  414.     /* release the buffers of the temp relations so that at commit time
  415.        the buffer manager will not try to flush them.  see hack comments
  416.        for sort nodes */
  417.  
  418.     ReleaseTmpRelBuffers(tempRelation);
  419.     if (FileNameUnlink((char *)
  420.                relpath((char *) &tempRelation->rd_rel->relname)) < 0)
  421.     elog(WARN, "ExecEndSort: unlink: %m");
  422.     amclose(tempRelation);
  423.  
  424.     ExecCloseR( (Plan)node);
  425.     /* shut down subplan */
  426.     outerPlan = get_outerPlan((Plan) node);
  427.     ExecEndNode(outerPlan);
  428.  
  429.     /* clean up tuple table */
  430.     ExecClearTuple((Pointer)
  431.            get_css_ScanTupleSlot((CommonScanState) aggstate));
  432.  
  433.     SO1_printf("ExecEndSort: %s\n",
  434.            "sort node shutdown");
  435. }
  436. /* end ExecEndAgg */
  437.  
  438.